package org.opens.sql.genHandle.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import org.opens.db.column.entity.ColumnEntity;
import org.opens.db.column.entity.TableEntity;
import org.opens.db.column.util.DbConfigUtil;
import org.opens.db.column.service.I_DbInfoService;
import org.opens.db.column.service.DbInfoServiceFactory;
import org.opens.freemarker.FreemarkerUtil;
import org.opens.sql.GenCodeConfigUtil;
import org.opens.sql.genConfig.GenEntityOfJeecgbootConfig;
import org.opens.sql.genConfig.GenEntityPublicConfig;
import org.opens.sql.genConfig.GenSqlConfig;
import org.opens.sql.genConfig.TableConfig;
import org.opens.sql.genHandle.GenHandle;
import org.opens.util.DatabaseConnectInfoEntity;
import org.opens.util.FileUtil;

import java.io.File;
import java.util.*;

public class GenEntityHandle implements GenHandle {

    private static final String ftlFilePath = "JavaEntity.ftl";

    private static final String MAVEN_PROJECT_PREFIX = "src\\main\\java";

    private static final String typeMappingPath = "mapping\\MYSQL.json";

    private static final String javaConfigMappingPath = "mapping\\JAVA_CONFIG.json";

    @Override
    public void genCode(GenSqlConfig genSqlConfig) {

        DatabaseConnectInfoEntity databaseConnectInfo = genSqlConfig.getDatabaseConnectInfo();

        // 从数据库中获取column信息
        I_DbInfoService IDbInfoService = DbInfoServiceFactory.getColumnServiceInstance(databaseConnectInfo.getDbType());

        // 获取表信息
        TableEntity tableInfo = IDbInfoService.getTableInfo(databaseConnectInfo);

        // 所有的列
        List<ColumnEntity> columnEntityList = IDbInfoService.getAllColumn(databaseConnectInfo);

        // 获取当前表配置
        TableConfig currentTableConfig = GenCodeConfigUtil.checkCurrentTableConfig(genSqlConfig.getTableConfigs(), tableInfo.getTableName());

        if (currentTableConfig != null) {
            // 删除需要忽略的列
            DbConfigUtil.removeIgnoreColumn(columnEntityList, currentTableConfig.getIgnoreColumns());
        }

        // 自动设置java类型
        Set<String> entityImportSet = DbConfigUtil.autoSetColumnConfig(genSqlConfig.getDatabaseConnectInfo().getDbType(), columnEntityList);

        // 根据配置计算需要导入的类
        Set<String> configImportList = calcEntityConfigImportList(genSqlConfig);

        // 计算需要import的类型
        Set<String> importSet = DbConfigUtil.calcImportList(entityImportSet, configImportList);

        String tableName = databaseConnectInfo.getTableName();

        columnEntityList.sort((item1, item2) -> {
            // 主键总是在最前面
            if ("PRI".equals(item1.getColumnKey())) {
                return -1;
            } else if ("PRI".equals(item2.getColumnKey())) {
                return 1;
            }

            // 非主键列按照字段名的首字母a-z排序
            return item1.getColumnName().compareTo(item2.getColumnName());
        });

        String configSuffix = genSqlConfig.getGenEntityPublicConfig().getSuffix();
        String suffix = StrUtil.isBlank(configSuffix) ? "" : configSuffix;
        String entityName = StrUtil.upperFirst(StrUtil.toCamelCase(tableName)) + suffix;

        Map<String, Object> entityPublicConfigMap = BeanUtil.beanToMap(genSqlConfig.getGenEntityPublicConfig());

        Map<String, Object> ftlMap = new HashMap<>();
        ftlMap.putAll(entityPublicConfigMap);

        ftlMap.put("importSet", importSet);
        ftlMap.put("columnEntityList", columnEntityList);
        ftlMap.put("tableName", databaseConnectInfo.getTableName());
        ftlMap.put("entityName", entityName);
        ftlMap.put("serialVersionUID", new Random().nextLong());
        ftlMap.put("authorInfo", genSqlConfig.getAuthorInfo());
        ftlMap.put("genEntityPublicConfig", genSqlConfig.getGenEntityPublicConfig());
        ftlMap.put("tableInfo", tableInfo);
        ftlMap.put("ignoreColumns", currentTableConfig.getIgnoreColumns());

        // 将包的包含.的路径转换为真实路径
        String packagePath = StrUtil.replace(genSqlConfig.getGenEntityPublicConfig().getPackageInfo(), ".", File.separator);
        // 父目录
        String descParentPath = FileUtil.pathSplicing(genSqlConfig.getGenPath(), MAVEN_PROJECT_PREFIX, packagePath);
        // java文件全路径
        String descPath = FileUtil.pathSplicing(descParentPath, entityName + ".java");

        // 创建目录
        FileUtil.createFolder(descParentPath);

        FreemarkerUtil.compileProcess(descPath, ftlMap, ftlFilePath);
    }

    @Override
    public void genCodeValid(GenSqlConfig genSqlConfig) {

    }

    /**
     * 计算生成实体需要导入的类
     * @param genSqlConfig 生成配置
     * @return 需要导入的java类信息
     */
    private Set<String> calcEntityConfigImportList(GenSqlConfig genSqlConfig) {
        Set<String> importSet = new HashSet<>();
        // 引入mybatis-plus的注解需要引入的类
        if (genSqlConfig.getGenEntityPublicConfig().isWithMybatisAnnotation()) {
            importSet.add("com.baomidou.mybatisplus.annotation.IdType");
            importSet.add("com.baomidou.mybatisplus.annotation.TableField");
            importSet.add("com.baomidou.mybatisplus.annotation.TableName");
            importSet.add("com.baomidou.mybatisplus.annotation.TableId");
            importSet.add("org.apache.ibatis.type.Alias");
        }

        // 引入lombok需要引入的类
        if (genSqlConfig.getGenEntityPublicConfig().isWithLombokAnnotation()) {
            importSet.add("lombok.Data");
            importSet.add("lombok.experimental.Accessors");
            importSet.add("lombok.EqualsAndHashCode");
        }

        // 引入swagger需要引入的类
        if (genSqlConfig.getGenEntityPublicConfig().isWithSwaggerAnnotation()) {
            importSet.add("io.swagger.annotations.ApiModel");
            importSet.add("io.swagger.annotations.ApiModelProperty");
        }

        // 现在是都实现这个接口, 所以需要添加这个依赖
        importSet.add("java.io.Serializable");

        GenEntityPublicConfig genEntityPublicConfig = genSqlConfig.getGenEntityPublicConfig();

        // 设置默认的时间格式字符串
        if (StrUtil.isBlank(genEntityPublicConfig.getDatePattern())) {
            genEntityPublicConfig.setDatePattern("yyyy-MM-dd");
        }

        if (genEntityPublicConfig.isDateFieldWithJacksonAnnotation()) {
            importSet.add("com.fasterxml.jackson.annotation.JsonFormat");
        }

        if (genEntityPublicConfig.isDateFieldWithSpringAnnotation()) {
            importSet.add("org.springframework.format.annotation.DateTimeFormat");
        }

        GenEntityOfJeecgbootConfig jeecgbootConfig = genSqlConfig.getGenEntityPublicConfig().getGenEntityOfJeecgbootConfig();
        if (jeecgbootConfig != null && jeecgbootConfig.isWithExcelAnnotation()) {
            importSet.add("org.jeecgframework.poi.excel.annotation.Excel");
        }

        return importSet;
    }

}
